package com.share.payment.service.impl;

import com.alibaba.fastjson2.JSON;
import com.share.common.core.domain.R;
import com.share.common.core.exception.ServiceException;
import com.share.common.core.utils.StringUtils;
import com.share.common.security.utils.SecurityUtils;
import com.share.payment.config.WxPayV3Properties;
import com.share.payment.domain.CreateWxPaymentForm;
import com.share.payment.domain.PaymentInfo;
import com.share.payment.domain.WxPrepayVo;
import com.share.payment.service.IWxPayService;
import com.share.payment.service.PaymentService;
import com.share.payment.utils.RequestUtils;
import com.share.user.api.RemoteUserService;
import com.share.user.domain.UserInfo;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.model.TransactionAmount;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;

/**
 * 微信支付接口实现类, 模拟微信支付成功
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WxPayServiceImpl implements IWxPayService {

    private final PaymentService paymentService;
//    private final RSAAutoCertificateConfig rsaAutoCertificateConfig;
    private final WxPayV3Properties wxPayV3Properties;
    private final RemoteUserService remoteUserService;

    // 模拟支付开关，true表示启用模拟支付，false表示使用真实微信支付接口
    @Value("${wx.v3pay.mock.enable:true}")
    private boolean mockPaymentEnabled;

    //微信下单
    public WxPrepayVo createWxPayment(CreateWxPaymentForm createWxPaymentForm) {
        String orderNo = createWxPaymentForm.getOrderNo();
        Long userId = SecurityUtils.getUserId();

        log.info("开始微信支付下单，订单号：{}, 用户ID：{}", orderNo, userId);

        // 使用模拟支付
        if (mockPaymentEnabled) {
            log.info("使用模拟支付，直接返回支付成功信息，订单号：{}", orderNo);

            // 模拟微信支付成功流程
            try {
                // 保存支付信息
                PaymentInfo paymentInfo = paymentService.savePaymentInfo(orderNo);

                // 直接更新支付状态为成功（模拟支付成功）
                Transaction mockTransaction = createMockTransaction(paymentInfo);
                paymentService.updatePaymentStatus(mockTransaction);

                // 构建模拟的返回数据
                return createMockWxPrepayVo();
            } catch (Exception e) {
                log.error("模拟支付异常 - 订单号: {}", orderNo, e);
                throw new ServiceException("模拟支付系统繁忙，请稍后重试");
            }
        }
        // 原始微信支付代码（注释保留）
        else {
            try {
                PaymentInfo paymentInfo = paymentService.savePaymentInfo(orderNo);
                JsapiServiceExtension service = new JsapiServiceExtension.Builder()
//                        .config(rsaAutoCertificateConfig)
                        .build();

                PrepayRequest request = buildPrepayRequest(paymentInfo);
                PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);

                log.info("微信支付下单成功，订单号：{}", orderNo);
                log.debug("微信支付返回详情 - appId: {}, timeStamp: {}, nonceStr: {}, package: {}, signType: {}, paySign: {}",
                        response.getAppId(),
                        response.getTimeStamp(),
                        response.getNonceStr(),
                        response.getPackageVal(),
                        response.getSignType(),
                        response.getPaySign());

                return convertToWxPrepayVo(response);

            } catch (ServiceException e) {
                log.error("微信支付业务异常 - 订单号: {}, 错误码: {}, 错误信息: {}",
                        orderNo, e.getCode(), e.getDetailMessage(), e);
                throw e;
            } catch (IllegalArgumentException e) {
                log.error("参数校验异常 - 订单号: {}, 错误信息: {}", orderNo, e.getMessage(), e);
                throw new ServiceException("订单参数异常");
            } catch (Exception e) {
                log.error("微信下单系统异常 - 订单号: {}, 异常类型: {}", orderNo, e.getClass().getSimpleName(), e);
                throw new ServiceException("微信支付系统繁忙，请稍后重试");
            }
        }
    }

    @Override
    public void wxnotify(HttpServletRequest request) {
        // 如果启用模拟支付，直接返回成功，不处理真实通知
        if (mockPaymentEnabled) {
            log.info("模拟支付模式，不处理微信通知");
            return;
        }

        // 原始微信通知处理代码（注释保留）
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String signature = request.getHeader("Wechatpay-Signature");
        String requestBody = RequestUtils.readData(request);

        //2.构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

        //3.初始化 NotificationParser
//        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        NotificationParser parser = new NotificationParser();
        //4.以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if (null != transaction &&
                transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
            //5.处理支付业务
            paymentService.updatePaymentStatus(transaction);
        }
    }

    //根据订单编号调用微信服务接口，查询支付相关状态信息
    @Override
    public Transaction queryPayStatus(String orderNo) {
        log.info("开始查询微信支付状态，订单号：{}", orderNo);

        // 模拟支付查询
        if (mockPaymentEnabled) {
            log.info("使用模拟支付查询，直接返回支付成功状态，订单号：{}", orderNo);
            try {
                // 获取支付信息并创建模拟交易对象
                PaymentInfo paymentInfo = paymentService.getPaymentInfoByOrderNo(orderNo);
                if (paymentInfo == null) {
                    throw new ServiceException("订单不存在");
                }
                return createMockTransaction(paymentInfo);
            } catch (ServiceException e) {
                log.error("模拟支付查询业务异常，订单号：{}, 错误信息：{}",
                        orderNo, e.getDetailMessage(), e);
                throw new ServiceException("查询支付状态失败：" + e.getDetailMessage());
            } catch (Exception e) {
                log.error("模拟支付查询系统异常，订单号：{}", orderNo, e);
                throw new ServiceException("支付查询系统异常，请稍后重试");
            }
        }
        // 原始微信支付查询代码（注释保留）
        else {
            try {
                Transaction result = executeQuery(orderNo);
                handleQueryResult(orderNo, result);
                return result;

            } catch (ServiceException e) {
                log.error("微信支付查询业务异常，订单号：{}, 错误码：{}, 错误信息：{}",
                        orderNo, e.getCode(), e.getDetailMessage(), e);
                throw new ServiceException("查询支付状态失败：" + e.getDetailMessage());

            } catch (Exception e) {
                log.error("微信支付查询系统异常，订单号：{}, 异常类型：{}",
                        orderNo, e.getClass().getSimpleName(), e);
                throw new ServiceException("支付查询系统异常，请稍后重试");
            }
        }
    }

    /**
     * 创建模拟的Transaction对象，代表支付成功
     */
    private Transaction createMockTransaction(PaymentInfo paymentInfo) {
        Transaction transaction = new Transaction();
        transaction.setOutTradeNo(paymentInfo.getOrderNo());
        transaction.setTradeState(Transaction.TradeStateEnum.SUCCESS);
        transaction.setTradeStateDesc("支付成功");

        // 模拟微信支付订单号
        transaction.setTransactionId("MOCK" + System.currentTimeMillis() + new Random().nextInt(1000));

        // 设置支付金额
        TransactionAmount amount = new TransactionAmount();
        amount.setTotal(paymentInfo.getAmount().multiply(new BigDecimal(100)).intValue());
        transaction.setAmount(amount);

        // 设置支付时间
        transaction.setSuccessTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

        return transaction;
    }

    /**
     * 创建模拟的WxPrepayVo对象
     */
    private WxPrepayVo createMockWxPrepayVo() {
        WxPrepayVo vo = new WxPrepayVo();
        vo.setAppId(wxPayV3Properties.getAppid());
        vo.setTimeStamp(String.valueOf(System.currentTimeMillis() / 1000));
        vo.setNonceStr("MOCK" + System.currentTimeMillis());
        vo.setPackageVal("prepay_id=MOCK" + System.currentTimeMillis());
        vo.setSignType("RSA");
        vo.setPaySign("MOCK_SIGN_" + System.currentTimeMillis());
        return vo;
    }

    /**
     * 执行微信支付查询（原始方法，仅作注释保留）
     */
    private Transaction executeQuery(String orderNo) {
        JsapiServiceExtension service = new JsapiServiceExtension.Builder()
//                .config(rsaAutoCertificateConfig)
                .build();

        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayV3Properties.getMerchantId());
        queryRequest.setOutTradeNo(orderNo);

        return service.queryOrderByOutTradeNo(queryRequest);
    }

    /**
     * 处理查询结果（原始方法，仅作注释保留）
     */
    private void handleQueryResult(String orderNo, Transaction result) {
        if (result == null) {
            log.warn("微信支付查询返回空结果，订单号：{}", orderNo);
            return;
        }

        log.info("微信支付查询成功，订单号：{}, 交易状态：{}, 金额：{}分",
                orderNo, result.getTradeState(), result.getAmount().getTotal());

        if (log.isDebugEnabled()) {
            log.debug("微信支付查询详情，订单号：{}, 响应：{}", orderNo, JSON.toJSONString(result));
        }

        // 根据交易状态进行不同的业务处理
        switch (result.getTradeState()) {
            case SUCCESS:
                log.info("订单支付成功，订单号：{}", orderNo);
                break;
            case REFUND:
                log.info("订单已退款，订单号：{}", orderNo);
                break;
            case CLOSED:
                log.info("订单已关闭，订单号：{}", orderNo);
                break;
            case NOTPAY:
                log.info("订单未支付，订单号：{}", orderNo);
                break;
            default:
                log.info("订单状态：{}，订单号：{}", result.getTradeState(), orderNo);
        }
    }

    // 构建支付请求参数（原始方法，仅作注释保留）
    private PrepayRequest buildPrepayRequest(PaymentInfo paymentInfo) {
        PrepayRequest request = new PrepayRequest();

        Amount amount = new Amount();
        amount.setTotal(paymentInfo.getAmount()
                .multiply(new BigDecimal(100))
                .intValue()
        );
        request.setAmount(amount);

        request.setAppid(wxPayV3Properties.getAppid());
        request.setMchid(wxPayV3Properties.getMerchantId());
        request.setDescription(paymentInfo.getContent());
        request.setNotifyUrl(wxPayV3Properties.getNotifyUrl());
        request.setOutTradeNo(paymentInfo.getOrderNo());

        // 获取用户openid
        String openid = getUserOpenId(paymentInfo.getUserId());
        Payer payer = new Payer();
        payer.setOpenid(openid);
        request.setPayer(payer);

        return request;
    }

    // 获取用户openid（原始方法，仅作注释保留）
    private String getUserOpenId(Long userId) {
        R<UserInfo> userInfoR = remoteUserService.getInfo(userId);
        if (StringUtils.isNull(userInfoR) || StringUtils.isNull(userInfoR.getData())) {
            throw new ServiceException("获取用户信息失败");
        }
        if (R.FAIL == userInfoR.getCode()) {
            throw new ServiceException(userInfoR.getMsg());
        }
        return userInfoR.getData().getWxOpenId();
    }

    // 转换响应对象（原始方法，仅作注释保留）
    private WxPrepayVo convertToWxPrepayVo(PrepayWithRequestPaymentResponse response) {
        WxPrepayVo wxPrepayVo = new WxPrepayVo();
        BeanUtils.copyProperties(response, wxPrepayVo);
        wxPrepayVo.setTimeStamp(response.getTimeStamp());
        return wxPrepayVo;
    }
}
